# 单元测试

Go语言提供了MockStub类型用于单元测试,可以使用“go test”命令,或者通过VS code进行单元测试。

单元测试的好处是不用启动Fabric网络即可在本地开发环境下进行链码的测试。

其原理是维护了一个 map[string][]byte类型的State用来模拟账本状态数据库,对链码的操作PutState()、GetState()、DelState()方法都是针对与内存中的State。MockStub主要提供了MockInit()、MockInvoke()方法模拟背书节点对链码的调用。

编写测试用例时,文件必须以_test.go结尾,包含TestXxx函数(Xxx首字母必须是大写),并与链码位于同一包路径下。编写链码测试用例可以直接参考官方提供的例子程序:github.com\hyperledger\fabric\examples\chaincode\go\example02\chaincode_test.go

为了方便测试用例编写,这里提供了一些常用的测试方法:

  • checkInit
  • checkState
  • checkQuery
  • checkInvoke

sacc_test.go测试用例如下:

package main

import (
    "fmt"
    "testing"

    "github.com/hyperledger/fabric/core/chaincode/shim"
)

func checkInit(t *testing.T, stub *shim.MockStub, args [][]byte) {
    res := stub.MockInit("1", args)
    if res.Status != shim.OK {
        fmt.Println("Init failed", string(res.Message))
        t.FailNow()
    }
}

func checkState(t *testing.T, stub *shim.MockStub, name string, value string) {
    bytes := stub.State[name]
    if bytes == nil {
        fmt.Println("State", name, "failed to get value")
        t.FailNow()
    }
    if string(bytes) != value {
        fmt.Println("State value", name, "was not", value, "as expected")
        t.FailNow()
    }
}

func checkQuery(t *testing.T, stub *shim.MockStub, name string, value string) {
    res := stub.MockInvoke("1", [][]byte{[]byte("query"), []byte(name)})
    if res.Status != shim.OK {
        fmt.Println("Query", name, "failed", string(res.Message))
        t.FailNow()
    }
    if res.Payload == nil {
        fmt.Println("Query", name, "failed to get value")
        t.FailNow()
    }
    if string(res.Payload) != value {
        fmt.Println("Query value", name, "was not", value, "as expected")
        t.FailNow()
    }
}

func checkInvoke(t *testing.T, stub *shim.MockStub, args [][]byte) {
    res := stub.MockInvoke("1", args)
    if res.Status != shim.OK {
        fmt.Println("Invoke", args, "failed", string(res.Message))
        t.FailNow()
    }
}

func TestSacc_Init(t *testing.T) {
    cc := new(SimpleAsset)
    stub := shim.NewMockStub("sacc", cc)

    // Init a=100
    checkInit(t, stub, [][]byte{[]byte("a"), []byte("100")})
    // check a=100
    checkState(t, stub, "a", "100")

}

func TestSacc_Query(t *testing.T) {
    cc := new(SimpleAsset)
    stub := shim.NewMockStub("sacc", cc)

    // Init a=100
    checkInit(t, stub, [][]byte{[]byte("a"), []byte("100")})
    // Init b=100
    checkInit(t, stub, [][]byte{[]byte("b"), []byte("100")})
    // check a=100
    checkQuery(t, stub, "a", "100")
    // check b=100
    checkQuery(t, stub, "b", "100")

}

func TestSacc_Invoke(t *testing.T) {
    cc := new(SimpleAsset)
    stub := shim.NewMockStub("sacc", cc)

    // Init a=100
    checkInit(t, stub, [][]byte{[]byte("a"), []byte("100")})
    // Init b=100
    checkInit(t, stub, [][]byte{[]byte("b"), []byte("100")})

    checkQuery(t, stub, "a", "100")
    checkQuery(t, stub, "b", "100")

    // set a=10
    checkInvoke(t, stub, [][]byte{[]byte("set"), []byte("a"), []byte("10")})
    // set b=90
    checkInvoke(t, stub, [][]byte{[]byte("set"), []byte("b"), []byte("90")})

    checkQuery(t, stub, "a", "10")
    checkQuery(t, stub, "b", "90")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

在命令行执行go test,结果如下:

单元测试

图 5-05 单元测试

VS code提供run package tests、 run file tests 、run test、 debug test方式进行单元测试。

注意:完成链码单元测试后,我们还可以在Fabric的开发环境进行进一步测试。Fabric的开发环境位于fabric-samples目录下的chaincode-docker-devmode下。

具体测试步骤可以参照官方文档说明:

https://hyperledger-fabric.readthedocs.io/en/release-1.4/chaincode4ade.html#testing-using-dev-mode

Last Updated: 3/9/2020, 9:27:52 PM